#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>

#define die(str, args...) do { \
        perror(str); \
        exit(EXIT_FAILURE); \
    } while(0)


class virtualJoystick
{
 private:
  int                    fd;
  struct uinput_user_dev uidev;
  struct input_event     ev;
  int                    dx, dy;
  int                    i;
  
 puplic:

  void ~uinput() 
  { 
  }

  void uinput()
  {
    fd = open("/dev/input/uinput", O_WRONLY | O_NONBLOCK);
    if(fd < 0)
      die("error: open");
    
    memset(&uidev, 0, sizeof(uidev));
    snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "easyTrack");
    uidev.id.version = 4; 
    uidev.id.bustype = BUS_USB; 
    uidev.id.vendor = 0x00046d; // Logitech 
    uidev.id.product = 0; 
    
    ioctl (fd, UI_SET_EVBIT, EV_SYN); 
    ioctl (fd, UI_SET_EVBIT, EV_ABS); 
    ioctl (fd, UI_SET_EVBIT, EV_KEY); 
    
    ioctl (fd, UI_SET_ABSBIT, ABS_X); 
    ioctl (fd, UI_SET_ABSBIT, ABS_Y); 
    ioctl (fd, UI_SET_ABSBIT, ABS_Z); 
    ioctl (fd, UI_SET_ABSBIT, ABS_RUDDER); 
    
    ioctl (fd, UI_SET_KEYBIT, BTN_TOP); 
    ioctl (fd, UI_SET_KEYBIT, BTN_TOP2); 
    ioctl (fd, UI_SET_KEYBIT, BTN_BASE); 
    ioctl (fd, UI_SET_KEYBIT, BTN_BASE2); 
    ioctl (fd, UI_SET_KEYBIT, BTN_BASE3); 
    ioctl (fd, UI_SET_KEYBIT, BTN_BASE4); 
    
    for(i = 0; i < ABS_MAX;++i) 
      { 
	uidev.absmax[i] = 511; 
	uidev.absmin[i] = -512; 
      } 
    // The jogwheel is different 
    uidev.absmax[ABS_Z] = 2047; 
    uidev.absmin[ABS_Z] =-2048; 
    // .. and rudder as well 
    uidev.absmax[ABS_RUDDER] = 255; 
    uidev.absmin[ABS_RUDDER] =-256; 
    // Create device 
    write (fd, &uidev, sizeof (uidev)); 
    if (ioctl (fd, UI_DEV_CREATE)) 
      { 
	fprintf (stderr,"Unable to create UIDEVUT device.\n"); 
	exit(EXIT_FAILURE); 
      } 
  }
  
};

int main(void)
{
  virtualJoystick js0 = new (virtualJoystick);
    
  
/*             memset(&ev, 0, sizeof(struct input_event)); */
/*             ev.type = EV_REL; */
/*             ev.code = REL_X; */
/*             ev.value = dx; */
/*             if(write(fd, &ev, sizeof(struct input_event)) < 0) */
/*                 die("error: write"); */

/*             memset(&ev, 0, sizeof(struct input_event)); */
/*             ev.type = EV_REL; */
/*             ev.code = REL_Y; */
/*             ev.value = dy; */
/*             if(write(fd, &ev, sizeof(struct input_event)) < 0) */
/*                 die("error: write"); */

/*             memset(&ev, 0, sizeof(struct input_event)); */
/*             ev.type = EV_SYN; */
/*             ev.code = 0; */
/*             ev.value = 0; */
/*             if(write(fd, &ev, sizeof(struct input_event)) < 0) */
/*                 die("error: write"); */


    sleep(2);

    if(ioctl(fd, UI_DEV_DESTROY) < 0)
        die("error: ioctl");

    close(fd);

    return 0;
}
